%%%-------------------------------------------------------------------
%%% @author chenlong
%%% @copyright (C) 2019, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 21. 三月 2019 11:51
%%%-------------------------------------------------------------------
-module(role_room).
-author("chenlong").

-include("common.hrl").

%% API
-export([cs_room_list/1,cs_room_create/1,onResCreateRoom/1,cs_room_enter/1,onResEnterRoom/1,
	cs_room_modify_room/1,cs_room_change_pos/1,cs_room_change_leader/1,cs_room_kick/1,onRoomKick/0,
	cs_room_leave/1,onResLeaveRoom/1,cs_room_change_ready/1,cs_room_fast_join/1]).

-export([makeRoomShortMsg/1,makeMemberListMsg/1]).

%%=========================EXPORTED FUNCTION=================================
%%获取房间列表
cs_room_list(#cs_room_list{roomID = RoomID}) ->
	RoomList = room_manager:getRoomList(RoomID),
	ShowNum = data_common:get(show_room_num),
	ShowRoomList = lists:sublist(RoomList,ShowNum),
	MsgFun = fun(EtsRoom) ->
		%%假房间的名字才需要转换，因为假房间的名字是从文本里面读出来的。而玩家创建的房间名是UTF8编码的
		RoomName = case EtsRoom#ets_room.isFake of
								 ?TRUE -> erlang:binary_to_list(unicode:characters_to_binary(EtsRoom#ets_room.roomName));
								 _ -> EtsRoom#ets_room.roomName
							 end,
		#p_roomInfo{
			roomID = EtsRoom#ets_room.roomID,
			roomName = RoomName,
			isSec = ?IF(isSecBlank(EtsRoom#ets_room.roomSec),0,1),
			watchingNum = length([ok||#room_player{pos = Pos}<-EtsRoom#ets_room.playerList,Pos>2]),
			settingList = EtsRoom#ets_room.settingList,
			playerA = player2msgPlayer(EtsRoom#ets_room.playerList,1),
			playerB = player2msgPlayer(EtsRoom#ets_room.playerList,2)
		}
		end,
	MsgList = lists:map(MsgFun,ShowRoomList),
	Msg = #sc_room_list{roomList = MsgList},
	?sendself(Msg).

%%进入房间
cs_room_enter(#cs_room_enter{roomID = RoomID, roomSec = RoomSec0}) ->
	RoomSec = util:term_to_list(RoomSec0),
	Role = role_data:getRole(),
	%%自己是否已经在该房间
	case Role#role.roomID of
		RoomID ->
			?DEBUG("already in room = ~p",[RoomID]),
			throw(ok);
		_ -> ok
	end,
	EtsRoom = room_manager:getEtsRoom(RoomID),
	%%查看有没有该房间
	case EtsRoom of
		#ets_room{} -> ok;
		_ ->
			?sendself(#sc_room_enter{result = 1}),%%没有该房间
			throw(ok)
	end,
	%%如果是假房间，则直接说密码不正确
	case EtsRoom#ets_room.isFake of
		?TRUE ->
			?sendself(#sc_room_enter{result = 2}),%%密码不正确
			throw(ok);
		_ -> ok
	end,
	%%是否有密码，有则验证密码
	case isSecBlank(EtsRoom#ets_room.roomSec) of
		?TRUE -> ok;
		_ ->
			case EtsRoom#ets_room.roomSec of
				RoomSec -> ok;
				_ ->
					?sendself(#sc_room_enter{result = 2}),%%密码不正确
					throw(ok)
			end
	end,
	%%人员是否已满
	case length(EtsRoom#ets_room.playerList) >= battle_lib:getMaxRoomPlayerCount() of
		?TRUE ->
			?sendself(#sc_room_enter{result = 3}),
			throw(ok);
		_ -> ok
	end,
	%%自己是否已经有房间
	case Role#role.roomID of
		0 -> ok;
		_ ->
			%%自己如果有房间，则需要先退出房间
			room_server:leaveRoom(Role#role.roomID, Role#role.roleID)
	end,
	%%加入该房间
	room_server:enterRoom(RoomID,Role#role.roleID),
	ok.

onResEnterRoom(EtsRoom) ->
	Role = role_data:getRole(),
	role_data:setRole(Role#role{roomID = EtsRoom#ets_room.roomID}),
	?sendself(#sc_room_enter{result = 0}),
	%%推送房间信息
	MsgRoomShort = makeRoomShortMsg(EtsRoom),
	?sendself(MsgRoomShort),
	%%推送战斗信息
	%%如果正在战斗，则要推送当前回合、剩余回合时间及其他战斗信息
	EtsBattle = room_manager:getEtsBattle(EtsRoom#ets_room.roomID),
	MsgBattle = battle_lib:makeBattleInfoMsg(EtsBattle),
	?sendself(MsgBattle),
	%%给其他房友推送最新房友信息
	MsgMemberList = #sc_room_member_list{memberList = makeMemberListMsg(EtsRoom),roomState = EtsRoom#ets_room.roomState},
	role_lib:broadcastToClient(EtsRoom,MsgMemberList,Role#role.roleID),
	%%如果已经分出了阵营，则给当前玩家推送阵营
	case EtsRoom#ets_room.roomState of
		?ROOM_STATE_BATTLE ->
			case lists:keyfind(1,#room_player.pos,EtsRoom#ets_room.playerList) of
				#room_player{playerID = PlayerID1} ->
					case lists:keyfind(2,#room_player.pos,EtsRoom#ets_room.playerList) of
						#room_player{playerID = PlayerID2} ->
							MsgCamp = #sc_battle_camp{playerID1 = PlayerID1,playerID2 = PlayerID2},
							?sendself(MsgCamp);
						_ -> ok
					end;
				_ -> ok
			end;
		_ -> ok
	end,
	ok.

%%创建房间
cs_room_create(#cs_room_create{roomName = RoomName0,roomSec = RoomSec0,settingList = SettingList}) ->
	RoomName = util:term_to_list(RoomName0),
	RoomSec = util:term_to_list(RoomSec0),
	%%自己当前是否已经有房间
	#role{roomID = RoomID}=role_data:getRole(),
	case room_manager:getEtsRoom(RoomID) of
		#ets_room{} ->
			?DEBUG("already have room = ~p",[RoomID]),
			throw(ok);%%已经有房间
		_ -> ok
	end,
	room_manager:createRoom({RoomName,RoomSec,SettingList}).
onResCreateRoom(RoomID) ->
	Role = role_data:getRole(),
	role_data:setRole(Role#role{roomID = RoomID}),
	?sendself(#sc_room_create{result = 0}),
	EtsRoom = room_manager:getEtsRoom(RoomID),
	%%推送房间信息
	MsgRoomShort = makeRoomShortMsg(EtsRoom),
	?sendself(MsgRoomShort),
	%%推送战斗信息
	%%如果正在战斗，则要推送当前回合、剩余回合时间及其他战斗信息
	EtsBattle = room_manager:getEtsBattle(EtsRoom#ets_room.roomID),
	MsgBattle = battle_lib:makeBattleInfoMsg(EtsBattle),
	?sendself(MsgBattle),
	ok.

%%修改房间规则
cs_room_modify_room(#cs_room_modify_room{settingList = SettingList, roomName = RoomName, roomSec = RoomSec}) ->
	%%验证规则长度合法性
	case length(SettingList) of
		?SETTING_MAX_LEN ->
			%%验证里面的值
			case lists:all(fun(V) -> lists:member(V,[0,1]) end,SettingList) of
				?TRUE -> ok;
				_ ->
					?DEBUG("settingList value error = ~p",[SettingList]),
					throw(ok)
			end;
		_ ->
			?DEBUG("out of setting length = ~p",[SettingList]),
			throw(ok)
	end,
	#role{roleID = RoleID, roomID = RoomID}=role_data:getRole(),
	%%是否有房间
	EtsRoom = room_manager:getEtsRoom(RoomID),
	%%是否是房主
	case EtsRoom#ets_room.masterID of
		RoleID -> ok;
		_ ->
			?sendself(#sc_room_modify_room{result = 1,settingList = [],roomName = "",roomSec = ""}),
			throw(ok)
	end,
	%%是否已经在对战中
	case EtsRoom#ets_room.roomState of
		?ROOM_STATE_IDLE -> ok;
		_ ->
			?sendself(#sc_room_modify_room{result = 2,settingList = [],roomName = "",roomSec = ""}),
			throw(ok)
	end,
	%%这里房主才能修改规则，所有这里直接修改ETS，但是不能直接insert，否则上面获取的EtsRoom万一中途被其他进程修改了，下面回写又把其他字段回写回去了
	SettingList1 = SettingList,
	EtsRoom1 = EtsRoom#ets_room{settingList = SettingList1,roomName = RoomName,roomSec = RoomSec},
	ets:update_element(?ETS_ROOM,RoomID,[
		{#ets_room.settingList,SettingList1},
		{#ets_room.roomName,RoomName},
		{#ets_room.roomSec,RoomSec}
	]),
	%%广播最新规则
	Msg = #sc_room_modify_room{result = 0,settingList = EtsRoom1#ets_room.settingList,roomName = RoomName,roomSec = RoomSec},
	role_lib:broadcastToClient(EtsRoom1,Msg),
	ok.

%%更换位置
cs_room_change_pos(#cs_room_change_pos{pos = TarPos}) ->
	%%TarPos是否合法
	case TarPos =< battle_lib:getMaxRoomPlayerCount() of
		?TRUE -> ok;
		_ ->
			?DEBUG("error TarPos=~p",[TarPos]),
			throw(ok)
	end,
	#role{roleID = RoleID,roomID = RoomID}=role_data:getRole(),
	%%是否有房间
	EtsRoom = room_manager:getEtsRoom(RoomID),
	%%是否是空位
	case lists:keymember(TarPos,#room_player.pos,EtsRoom#ets_room.playerList) of
		?TRUE ->%%已经有人
			?sendself(#sc_room_change_pos{result = 1,playerID = RoleID,srcPos = 0,tarPos = 0}),
			throw(ok);
		_ -> ok
	end,
	{RoomPlayer,_T}=case lists:keytake(RoleID,#room_player.playerID,EtsRoom#ets_room.playerList) of
		{value, RoomPlayer0,T0} -> {RoomPlayer0,T0};
		_ ->
			?ERR("cs_room_change_pos cannot find player RoleID=~p,TarPos=~p,EtsRoom=~p",[RoleID,TarPos,EtsRoom]),
			throw(ok)
	end,
	%%自己是否在准备状态
	case RoomPlayer#room_player.state of
		?PLAYER_STATE_IDLE -> ok;
		_ ->
			?sendself(#sc_room_change_pos{result = 2,playerID = RoleID,srcPos = 0,tarPos = 0}),
			throw(ok)
	end,
	%%是否在战斗状态
	case EtsRoom#ets_room.roomState of
		?ROOM_STATE_IDLE -> ok;
		_ ->
			?sendself(#sc_room_change_pos{result = 3,playerID = RoleID,srcPos = 0,tarPos = 0}),
			throw(ok)
	end,
	%%发送给房间进程处理，这里处理位置会导致多个进程操作位置信息
	EtsRoom#ets_room.roomPID ! {changePos, RoleID, TarPos}.

cs_room_change_leader(#cs_room_change_leader{playerID = TarRoleID}) ->
	#role{roleID = RoleID,roomID = RoomID}=role_data:getRole(),
	%%是否是自己
	case TarRoleID of
		RoleID ->
			?sendself(#sc_room_change_leader{result = 3,srcPlayerID = 0,tarPlayerID = 0}),
			throw(ok);
		_ -> ok
	end,
	%%是否有房间
	EtsRoom = room_manager:getEtsRoom(RoomID),
	%%自己是否是房主
	case EtsRoom#ets_room.masterID of
		RoleID -> ok;
		_ ->
			?sendself(#sc_room_change_leader{result = 1,srcPlayerID = 0,tarPlayerID = 0}),
			throw(ok)
	end,
	%%对方是否在房间
	case lists:keymember(TarRoleID,#room_player.playerID,EtsRoom#ets_room.playerList) of
		?TRUE -> ok;
		_ ->
			?sendself(#sc_room_change_leader{result = 2,srcPlayerID = 0,tarPlayerID = 0}),
			throw(ok)
	end,
	%%房主才能变更房主，所有这里直接修改ETS
	EtsRoom1 = EtsRoom#ets_room{masterID = TarRoleID},
	ets:update_element(?ETS_ROOM,RoomID,{#ets_room.masterID,TarRoleID}),
	%%广播
	Msg = #sc_room_change_leader{result = 0,srcPlayerID = RoleID,tarPlayerID = TarRoleID},
	role_lib:broadcastToClient(EtsRoom1,Msg).

cs_room_kick(#cs_room_kick{playerID = TarRoleID}) ->
	%%是否有房间
	#role{roleID = RoleID,roomID = RoomID}=role_data:getRole(),
	EtsRoom = room_manager:getEtsRoom(RoomID),
	%%是否是自己
	case TarRoleID of
		RoleID ->
			?sendself(#sc_room_kick{result = 3,playerID = 0,pos = 0}),
			throw(ok);
		_ -> ok
	end,
	%%自己是否是房主
	case EtsRoom#ets_room.masterID of
		RoleID -> ok;
		_ ->
			?sendself(#sc_room_kick{result = 1,playerID = 0,pos = 0}),
			throw(ok)
	end,
	%%是否在比赛中
	{TarRoomPlayer,_T} = case lists:keytake(TarRoleID, #room_player.playerID,EtsRoom#ets_room.playerList) of
		{value, TarRoomPlayer0, T0} -> {TarRoomPlayer0,T0};
		_ ->%%已经离开了房间
			?sendself(#sc_room_kick{result = 0,playerID = TarRoleID,pos = 0}),
			throw(ok)
	end,
	case EtsRoom#ets_room.roomState of
		?ROOM_STATE_IDLE ->%%不是比赛，都可以踢
			ok;
		_ ->%%如果是比赛中则只能踢观战者
			case TarRoomPlayer#room_player.pos > 2 of
				?TRUE -> ok;
				_ ->
					?sendself(#sc_room_kick{result = 2, playerID = 0,pos = 0}),
					throw(ok)
			end
	end,
	%%发送给房间进程处理，虽然这个操作只能房主操作，但是playerList字段房间进程也可能修改
	EtsRoom#ets_room.roomPID ! {roomKick, TarRoleID}.

onRoomKick() ->
	Role = role_data:getRole(),
	role_data:setRole(Role#role{roomID = 0}).

cs_room_leave(#cs_room_leave{}) ->
	%%自己是否有房间
	#role{roleID = RoleID, roomID = RoomID}=role_data:getRole(),
	EtsRoom = room_manager:getEtsRoom(RoomID),
	%%自己是否在准备状态
	#room_player{state = PlayerState,pos = Pos}=lists:keyfind(RoleID,#room_player.playerID,EtsRoom#ets_room.playerList),
	case PlayerState of
		?PLAYER_STATE_IDLE -> ok;
		_ ->
			?sendself(#sc_room_leave{result = 1,playerID = RoleID, pos = 0}),
			throw(ok)
	end,
	%%是否在战斗中，而且自己是参战者
	case EtsRoom#ets_room.roomState of
		?ROOM_STATE_IDLE -> ok;
		_ ->
			case Pos > 2 of
				?TRUE -> ok;
				_ ->%%自己是参战者
					?sendself(#sc_room_leave{result = 2,playerID = RoleID, pos = 0}),
					throw(ok)
			end
	end,
	room_server:leaveRoom(RoomID,RoleID).
onResLeaveRoom(RoomID) ->
	Role = role_data:getRole(),
	case Role#role.roomID of
		RoomID -> role_data:setRole(Role#role{roomID = 0});
		_ -> ok
	end,
	ok.

%%修改准备状态
cs_room_change_ready(#cs_room_change_ready{}) ->
	%%是否有房间
	#role{roleID = RoleID,roomID = RoomID}=role_data:getRole(),
	EtsRoom = room_manager:getEtsRoom(RoomID),
	#room_player{pos = Pos}=lists:keyfind(RoleID,#room_player.playerID,EtsRoom#ets_room.playerList),
	%%是否在战斗位置
	case Pos =< 2 of
		?TRUE -> ok;
		_ ->%%不在战斗位置，无法修改
			?sendself(#sc_room_change_ready{result = 1,playerID = 0,readyState = 0}),
			throw(ok)
	end,
	%%是否已经开始战斗
	case EtsRoom#ets_room.roomState of
		?ROOM_STATE_IDLE -> ok;
		_ ->
			?sendself(#sc_room_change_ready{result = 2,playerID = 0,readyState = 0}),
			throw(ok)
	end,
	%%房间进程修改
	EtsRoom#ets_room.roomPID ! {changeReady, RoleID}.

cs_room_fast_join(#cs_room_fast_join{settingList = SettingList}) ->
	Role = role_data:getRole(),
	%%自己是否已经有房间
	case Role#role.roomID of
		0 -> ok;
		_ ->
			%%自己如果有房间，则需要先退出房间
			room_server:leaveRoom(Role#role.roomID, Role#role.roleID)
	end,
	EtsRoomList = room_manager:getEtsRoomListBySetting(SettingList),
	case EtsRoomList of
		[#ets_room{roomPID = RoomPID}|T] ->
			%%给筛选出来的房间进程，依据列表顺序依次判断真正能进入哪个房间
			RoomPID ! {fastJoin, Role#role.roleID, T};
		_ ->
			?sendself(#sc_room_fast_join{result = 1})
	end.

%%=========================LOCAL FUNCTION=================================
player2msgPlayer(PlayerList,Pos) ->
	case lists:keyfind(Pos,#room_player.pos,PlayerList) of
		#room_player{playerID = PlayerID}when is_integer(PlayerID) ->
			RolePublic = role_lib:getRolePublic(PlayerID),
			#p_room_member{
				pos = Pos,
				playerID = PlayerID,
				playerName = RolePublic#ets_role_public.roleName,
				playerHead = RolePublic#ets_role_public.headurl
			};
		#room_player{playerID = {RoleName,RoleHead}} ->%%假房间数据
			#p_room_member{
				pos = Pos,
				playerID = 0,
				playerName = erlang:binary_to_list(unicode:characters_to_binary(RoleName)),
				playerHead = RoleHead
			};
		_ ->
			#p_room_member{
				pos = Pos,
				playerID = 0,
				playerName = "",
				playerHead = ""
			}
	end.
makeRoomShortMsg(#ets_room{roomID = RoomID,masterID = MasterID,settingList = SettingList,
	roomName = RoomName,roomSec = RoomSec,roomState = RoomState}=EtsRoom) ->
	MsgList = makeMemberListMsg(EtsRoom),
	#sc_room_short_info{
		roomID = RoomID,
		memberList = MsgList,
		leaderID = MasterID,
		settingList = SettingList,
		roomName = RoomName,
		roomSec = RoomSec,
		roomState = RoomState
	}.
makeMemberListMsg(#ets_room{playerList = PlayerList}) ->
	[begin
		 #ets_role_public{roleName = Name,headurl = Head}=role_lib:getRolePublic(RoomPlayer#room_player.playerID),
		 #p_room_member{
			 pos = abs(RoomPlayer#room_player.pos),
			 playerID = RoomPlayer#room_player.playerID,
			 playerName = Name,
			 playerHead = Head
		 }
	 end || RoomPlayer<-PlayerList].

%%是否密码为空
isSecBlank("") ->?TRUE;
isSecBlank(<<>>) ->?TRUE;
isSecBlank(_) ->?FALSE.